﻿using System;
using System.Security;
using System.Xml;
using Notoric.Model.Internal;
using Notoric.Model.Packaging;

namespace Notoric.Model.Elements
{
    /// <summary>
    /// Represents a person.
    /// </summary>
    public class PersonElement : ModelElement
    {
        #region Constructors

        /// <summary>
        /// Creates a new <see cref="PersonElement"/> instance.
        /// </summary>
        /// <param name="packagePart">
        /// <para>
        /// Type: <see cref="XmlPackagePart"/>
        /// </para>
        /// <para>
        /// The package part that owns this element.
        /// </para>
        /// </param>
        /// <param name="owner">
        /// <para>
        /// Type: <see cref="ModelElement"/>
        /// </para>
        /// <para>
        /// The model element that directly owns this element.
        /// </para>
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="packagePart"/> or <paramref name="owner"/> is <see langword="null"/>.
        /// </exception>
        public PersonElement(XmlPackagePart packagePart, ModelElement owner)
            : base(packagePart, owner)
        {
            if (owner == null)
                throw new ArgumentNullException("owner");
        }

        /// <summary>
        /// Creates a new <see cref="PersonElement"/> instance.
        /// </summary>
        /// <param name="packagePart">
        /// <para>
        /// Type: <see cref="XmlPackagePart"/>
        /// </para>
        /// <para>
        /// The package part that owns this element.
        /// </para>
        /// </param>
        /// <param name="owner">
        /// <para>
        /// Type: <see cref="ModelElement"/>
        /// </para>
        /// <para>
        /// The model element that directly owns this element.
        /// </para>
        /// </param>
        /// <param name="element">
        /// <para>
        /// Type: <see cref="XmlElement"/>
        /// </para>
        /// <para>
        /// The XML element that holds the data of this object.
        /// </para>
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Any of the arguments is <see langword="null"/>.
        /// </exception>
        internal PersonElement(XmlPackagePart packagePart, ModelElement owner, XmlElement element)
            : base(packagePart, owner, element)
        {
            if (owner == null)
                throw new ArgumentNullException("owner");

            birthDateAttribute = element.Attributes["birth_date"];
            deathDateAttribute = element.Attributes["death_date"];
            firstNameAttribute = element.Attributes["first_name"];
            lastNameAttribute = element.Attributes["last_name"];
        }

        #endregion

        #region ModelElement Members

        /// <inheritdoc/>
        protected override XmlElement CreateObjectElement(XmlDocument document)
        {
            var element = document.CreateElement(
                PackageVocabulary.PackageNamespacePrefix,
                "person",
                PackageVocabulary.PackageNamespaceUri
                );

            birthDateAttribute = document.CreateAttribute("birth_date");
            deathDateAttribute = document.CreateAttribute("death_date");
            firstNameAttribute = document.CreateAttribute("first_name");
            lastNameAttribute = document.CreateAttribute("last_name");

            element.Attributes.Append(birthDateAttribute);
            element.Attributes.Append(deathDateAttribute);
            element.Attributes.Append(firstNameAttribute);
            element.Attributes.Append(lastNameAttribute);

            return element;
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets or sets the birth date.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="string"/>
        /// </para>
        /// <para>
        /// The birth date of the person.
        /// </para>
        /// </value>
        public string BirthDate
        {
            get { return birthDateAttribute.Value; }
            set
            {
                birthDateAttribute.Value = SecurityElement.Escape(value);

                RaisePropertyChanged("BirthDate");
            }
        }

        /// <summary>
        /// Gets or sets the death date.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="string"/>
        /// </para>
        /// <para>
        /// The death date of the person.
        /// </para>
        /// </value>
        public string DeathDate
        {
            get { return deathDateAttribute.Value; }
            set
            {
                deathDateAttribute.Value = SecurityElement.Escape(value);

                RaisePropertyChanged("DeathDate");
            }
        }

        /// <summary>
        /// Gets or sets the first name(s).
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="string"/>
        /// </para>
        /// <para>
        /// The first name(s) of the person.
        /// </para>
        /// </value>
        public string FirstName
        {
            get { return firstNameAttribute.Value; }
            set
            {
                firstNameAttribute.Value = SecurityElement.Escape(value);

                RaisePropertyChanged("FirstName");
            }
        }

        /// <summary>
        /// Gets or sets the last name.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="string"/>
        /// </para>
        /// <para>
        /// The last name of the person.
        /// </para>
        /// </value>
        public string LastName
        {
            get { return lastNameAttribute.Value; }
            set
            {
                lastNameAttribute.Value = SecurityElement.Escape(value);

                RaisePropertyChanged("LastName");
            }
        }

        #endregion

        #region Private Fields

        /// <summary>
        /// Holds the value of the <see cref="BirthDate"/> property.
        /// </summary>
        private XmlAttribute birthDateAttribute;
        /// <summary>
        /// Holds the value of the <see cref="DeathDate"/> property.
        /// </summary>
        private XmlAttribute deathDateAttribute;
        /// <summary>
        /// Holds the value of the <see cref="FirstName"/> property.
        /// </summary>
        private XmlAttribute firstNameAttribute;
        /// <summary>
        /// Holds the value of the <see cref="LastName"/> property.
        /// </summary>
        private XmlAttribute lastNameAttribute;

        #endregion
    }
}
